﻿Imports Microsoft.SqlServer.TransactSql.ScriptDom
Imports System.IO
Imports System.Text.ASCIIEncoding
Imports System.Text.RegularExpressions

Public Class SqlAnalyzer
    Inherits TSqlFragmentVisitor

    Private originalQuery As String
    Public errors As IList(Of ParseError) = Nothing
    Private mVariables As Hashtable


    Default Public ReadOnly Property Variables(ByVal key As String) As DeclaredVariable
        Get
            Return mVariables(key)
        End Get
    End Property

    Public ReadOnly Property DeclaredVariableNames() As ICollection
        Get
            Return mVariables.Keys
        End Get
    End Property

    Public Sub New(ByVal query As String)
        originalQuery = query
        mVariables = New Hashtable

        Dim rdr As New StreamReader(New MemoryStream(ASCII.GetBytes(query)))

        Dim parser As New TSql120Parser(True)
        Dim tree As TSqlFragment = parser.Parse(rdr, errors)

        tree.Accept(Me)

        rdr.Dispose()
    End Sub

    Public Overrides Sub ExplicitVisit(node As DeclareVariableElement)
        Dim variableComment As String = String.Empty
        Dim pattern As String = String.Format("declare\s+{0}.*--(?<comment>.*)\n", node.VariableName.Value)
        Dim match As Match = Regex.Match(originalQuery, pattern, RegexOptions.IgnoreCase)
        If match.Success Then
            variableComment = match.Groups("comment").Value.Trim
        End If
        mVariables.Add(node.VariableName.Value, New DeclaredVariable(node.VariableName.Value, If(Not IsNothing(node.DataType), node.DataType.Name.BaseIdentifier.Value, Nothing), variableComment))

        MyBase.ExplicitVisit(node)
    End Sub

    Public Overrides Sub ExplicitVisit(node As SetVariableStatement)
        Dim expressionValue As String = String.Empty

        If TypeOf node.Expression Is Literal Then
            expressionValue = CType(node.Expression, Literal).Value
        End If

        If Not IsNothing(mVariables(node.Variable.Name)) Then
            CType(mVariables(node.Variable.Name), DeclaredVariable).DefaultValue = expressionValue
        End If
        MyBase.ExplicitVisit(node)
    End Sub

End Class
